package org.liveboardgames.agricola.domain.action;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.liveboardgames.agricola.domain.common.Target;
import org.liveboardgames.agricola.model.enums.PrerequisiteActionTypeEnum;
import org.liveboardgames.agricola.model.structure.Visitable;
import org.liveboardgames.agricola.model.structure.Visitor;

public class Action implements Visitable, Cloneable {

  private Long id;

  private String name;

  /** Really a <code>Map&lt;ResourceTypeEnum, Integer&gt;</code> */
  private Map<String, Integer> cost;

  private Integer numberOfUses;

  /** Really an <code>ActionTempoEnum</code>. */
  private String tempo;

  private Boolean needPlayerInput;

  private String actionOutput;

  private Integer outputQuantity;

  /**
   * In DB, this should only be a Card. It is a Target so that it can be set to
   * be a player if it is null.
   */
  private Target target;

  private Target link;

  private Set<Action> prerequisiteActions;

  /** Really a <code>Set&lt;PrerequisiteEnum&gt;</code> */
  private Set<String> prerequisiteEnums;

  private PrerequisiteActionTypeEnum prerequisiteActionType;

  public Action() {
    this.numberOfUses = 1;
    this.needPlayerInput = true;
    this.prerequisiteActions = new HashSet<Action>();
    this.prerequisiteEnums = new HashSet<String>();
  }

  public void setId(Long id) {
    this.id = id;
  }

  public Long getId() {
    return id;
  }

  /**
   * @return the {@link #name}
   */
  public String getName() {
    return name;
  }

  /**
   * @param name
   *          the {@link #name} to set
   */
  public void setName(String name) {
    this.name = name;
  }

  /**
   * @return the {@link #cost}
   */
  public Map<String, Integer> getCost() {
    return cost;
  }

  /**
   * @param cost
   *          the {@link #cost} to set
   */
  public void setCost(Map<String, Integer> cost) {
    this.cost = cost;
  }

  /**
   * @return the {@link #numberOfUses}
   */
  public Integer getNumberOfUses() {
    return numberOfUses;
  }

  /**
   * @param numberOfUses
   *          the {@link #numberOfUses} to set
   */
  public void setNumberOfUses(Integer numberOfUses) {
    this.numberOfUses = numberOfUses;
  }

  /**
   * @return the {@link #tempo}
   */
  public String getTempo() {
    return tempo;
  }

  /**
   * @param tempo
   *          the {@link #tempo} to set
   */
  public void setTempo(String tempo) {
    this.tempo = tempo;
  }

  /**
   * @return the {@link #needPlayerInput}
   */
  public Boolean getNeedPlayerInput() {
    return needPlayerInput;
  }

  /**
   * @param needPlayerInput
   *          the {@link #needPlayerInput} to set
   */
  public void setNeedPlayerInput(Boolean needPlayerInput) {
    this.needPlayerInput = needPlayerInput;
  }

  /**
   * @return the {@link #target}
   */
  public Target getTarget() {
    return target;
  }

  /**
   * @param target
   *          the {@link #target} to set
   */
  public void setTarget(Target target) {
    this.target = target;
  }

  /**
   * @return the {@link #link}
   */
  public Target getLink() {
    return link;
  }

  /**
   * @param link
   *          the {@link #link} to set
   */
  public void setLink(Target link) {
    this.link = link;
  }

  /**
   * @return the {@link #prerequisiteActions}
   */
  public Set<Action> getPrerequisiteActions() {
    return prerequisiteActions;
  }

  /**
   * @param prerequisiteActions
   *          the {@link #prerequisiteActions} to set
   */
  public void setPrerequisiteActions(Set<Action> prerequisiteActions) {
    this.prerequisiteActions = prerequisiteActions;
  }

  /**
   * @return the {@link #prerequisiteEnums}
   */
  public Set<String> getPrerequisiteEnums() {
    return prerequisiteEnums;
  }

  /**
   * @param prerequisiteEnums
   *          the {@link #prerequisiteEnums} to set
   */
  public void setPrerequisiteEnums(Set<String> prerequisiteEnums) {
    this.prerequisiteEnums = prerequisiteEnums;
  }

  /**
   * @return the {@link #prerequisiteActionType}
   */
  public PrerequisiteActionTypeEnum getPrerequisiteActionType() {
    return prerequisiteActionType;
  }

  /**
   * @param prerequisiteActionType
   *          the {@link #prerequisiteActionType} to set
   */
  public void setPrerequisiteActionType(PrerequisiteActionTypeEnum prerequisiteActionType) {
    this.prerequisiteActionType = prerequisiteActionType;
  }

  /**
   * @return the actionOutput
   */
  public String getActionOutput() {
    return actionOutput;
  }

  /**
   * @param actionOutput
   *          the actionOutput to set
   */
  public void setActionOutput(String actionOutput) {
    this.actionOutput = actionOutput;
  }

  /**
   * @return the outputQuantity
   */
  public Integer getOutputQuantity() {
    return outputQuantity;
  }

  /**
   * @param outputQuantity
   *          the outputQuantity to set
   */
  public void setOutputQuantity(Integer outputQuantity) {
    this.outputQuantity = outputQuantity;
  }

  public void acceptVisit(Visitor visitor) {
    visitor.visit(this);
    for (Action action : this.prerequisiteActions) {
      action.acceptVisit(visitor);
    }
  }

  public Action clone() {
    Action clone = null;
    try {
      clone = (Action)super.clone();
    }
    catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }

    return clone;
  }
  
  @Override
  public String toString() {
    return "Action " + this.name;
  }
}
